package org.mmtk.plan.metrix;

import org.mmtk.utility.Log;
import org.mmtk.utility.options.Options;
import org.vmmagic.pragma.Uninterruptible;

@Uninterruptible
class RunCounts {
	private long cycles;

	private DepthCounts depthCounts;
	private DepthCounts fixedDepthCounts;

	RunCounts() {
		this.cycles = 0;
		this.depthCounts = new DepthCounts();
		this.fixedDepthCounts = new DepthCounts();
	}

	void dump(int verbose) {
		if (Options.verbose.getValue() >= verbose) {
			Log.write(" Cycles: ");
			Log.write(this.cycles);
			Log.write(" Depth: ");
			this.depthCounts.dump(this.cycles);
			Log.write(" FixedDepth: ");
			this.fixedDepthCounts.dump(this.cycles);
			Log.flush();
		}
	}

	public void addCycle(ClosureCounts counts, ClosureCounts fixedCounts) {
		this.cycles++;
		this.depthCounts.addCycle(counts.getDepth(), this.cycles);
		this.fixedDepthCounts.addCycle(fixedCounts.getDepth(), this.cycles);
	}

	@Uninterruptible
	private class DepthCounts {
		private long maxDepth;
		private long maxDepthGC;
		private long minDepth;
		private long minDepthGC;
		private long sumDepth;

		DepthCounts() {
			this.maxDepth = 0;
			this.maxDepthGC = 0;
			this.minDepth = 0;
			this.minDepthGC = 0;
			this.sumDepth = 0;
		}

		void dump(long cycles) {
			Log.write(" Max: ");
			Log.write(this.maxDepth);
			Log.write(" MaxGC: ");
			Log.write(this.maxDepthGC);
			Log.write(" Min: ");
			Log.write(this.minDepth);
			Log.write(" MinGC: ");
			Log.write(this.minDepthGC);
			Log.write(" Avg: ");
			Log.write(this.sumDepth / cycles);
		}

		public void addCycle(long depth, long cycle) {
			this.sumDepth += depth;
			if (depth > this.maxDepth || this.maxDepth == 0) {
				this.maxDepth = depth;
				this.maxDepthGC = cycles;
			}
			if (depth < this.minDepth || this.minDepth == 0) {
				this.minDepth = depth;
				this.minDepthGC = cycles;
			}
		}
	}
}
